5W - 클러스터 메시

개요

이번에는 실리움의 멀티 클러스터 지원 방식 기능을 알아본다.
실리움은 cni이면서 메시 기능도 제공해준다..

최신 버전인 1.18에서는 동작이 조금 이상하다.

경고!!

미완성된 글입니다!!
추가 작성해야 하는 글입니다!!!

클러스터 메시란

이스티오를 공부하면서 정리한 개념을 조금 가져와봤다.
클러스터 메시는 여러 클러스터를 메시로 묶는 것을 말한다.
이미 클러스터가 여러 워크로드와 서비스의 묶음인데 뭐하러 다중 클러스터를 두냐 싶을 수 있다.
그럼에도 여러 클러스터, 여러 메시를 두는 것은 다양한 이점을 제공할 수 있다.

뇌피셜 - 멀티 메시를 써야 하는 운영 케이스

메시를 멀티로 가져가는 것은 운영 조직의 마음이긴 할 텐데, 구체적으로 어떨 때 멀티로 세팅하게 될까?
개인적으로 멀티 메시가 구성되는 상황을 3 가지 정도 생각해봤다.

  1. 처음부터 서비스와 관리 주체가 명확하게 나뉘는 상황
  • 대기업에서 다양한 사업을 추진하며 서비스를 운영할 때
  • 서비스 간 상호작용이 필요한 순간은 있으나 각 서비스의 기능이 확실하게 분리될 때
  • 이를 같은 메시 환경에서 운영하며 발생할 수 있는 시끄러운 이웃 문제나 장애 확산의 리스크를 질 이유가 없다.
  • 어차피 관리팀이 명확히 분리되는 상황이라면 사실 이를 같은 메시 환경으로 관리하는 게 더 어색하지 않은가?
  1. 조직 간 결합
  • 사업체 간 협업을 하면서 네트워크 망을 연결하게 되는 상황
  1. 조직 분리
  • 점차 서비스가 확장되어가며 서비스의 정의가 세분화되는 상황
  • 초기에는 같은 메시로 구성되는 게 이상적이었으나 규모가 커지며 점차 팀을 분리해 관리하는 것이 더 이득일 때

이러니 저러니 하지만, 결국 관리팀이 명확하게 구분되는 상황일 때 멀티 메시를 고려해봄직하지 않을까 하는 생각이다.
거시적인 관점에서는 멀티 메시라고는 하나 사실 대체로 복수의 메시를 갖추게 되는 운영 플로우는 조직적으로 이미 분절된 상황에서 각각 환경을 구축한 이후에 이들을 통합 구성하는 방향이 아닐까 싶다.

이스티오에서는 다음과 같은 다양한 메타 클러스터 아키텍처를 둔다.

이걸 일일히 다루는 건 투머치고, 보통 멀티 클러스터 메시를 구축할 때 신경 쓸 사항만 고려해보자.

클러스터 간 워크로드 디스커버리


워크로드가 컨트롤 플레인에 연결될 수 있어야 하고, 컨트롤 플레인은 모든 클러스터의 워크로드를 찾아 레지스트리를 제공할 수 있어야 한다.
컨트롤 플레인은 모든 클러스터의 api 서버에 접근할 수 있어야 한다.
이에 대해서는 보통 서로의 클러스터에 대한 kubeconfig 파일을 시크릿으로 구비해두는 식으로 해결한다.

클러스터 간 워크로드 연결성(connectivity)

각 클러스터는 엔드포인트로 실제로 연결될 수 있어야 하며, 별도의 외부 경로가 아니라 클러스터 간의 경로를 통해 통신할 수 있어야 한다.[]
실리움은 자체적인 데이터 경로를 가지고 있는 만큼, 클러스터 간 통신에 있어 신경 쓸 요소들이 왕왕 있다.

클러스터 간 공통 신뢰


이스티오의 보안 기능을 활용하기 위해서는 클러스터 간 워크로드가 서로 인증할 수 있어야 한다.
이를 위해서는 공통된 같은 Root CA를 가지고 있어야 한다.

크게 두 가지 방법을 사용할 수 있다.

실리움 클러스터 메시

실리움 역시 이스티오처럼 멀티 클러스터 메시 기능을 지원한다.[1] 다 해먹어라
이는 즉 실리움이 가진 독특한 데이터 경로를 통해 얻는 트래픽 라우팅, 신원 부여 등의 기능을 여러 클러스터에서 연동하여 사용할 수 있다는 것이다.

실리움은 KVStoreMesh라 하여 클러스터 메시의 기능을 조금 확장성 있게 만드는데, 이것은 원격 클러스터의 정보를 로컬에 Etcd와 같은 키값 저장소를 통해 캐싱하는 것이다.
이 방식은 원격 클러스터에서 매번 에이전트들의 정보를 가져오는 기본 방식보다 확장성과 효율을 챙길 수 있다.
1.16 버전 기준 기본 활성화 상태이다.

요구 사항

제한 사항

설정

실습

이번에는 간단하게 하기 위해 KIND로 구성한다.

kind create cluster --name west --image kindest/node:v1.33.2 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000 # sample apps
    hostPort: 30000
  - containerPort: 30001 # hubble ui
    hostPort: 30001
- role: worker
  extraPortMappings:
  - containerPort: 30002 # sample apps
    hostPort: 30002
networking:
  podSubnet: "10.0.0.0/16"
  serviceSubnet: "10.2.0.0/16"
  disableDefaultCNI: true
  kubeProxyMode: none
EOF


# 설치 확인
kubectl ctx
kubectl get node 
kubectl get pod -A

# 노드에 기본 툴 설치
docker exec -it west-control-plane sh -c 'apt update && apt install tree psmisc lsof wget net-tools dnsutils tcpdump ngrep iputils-ping git -y'
docker exec -it west-worker sh -c 'apt update && apt install tree psmisc lsof wget net-tools dnsutils tcpdump ngrep iputils-ping git -y'

#
kind create cluster --name east --image kindest/node:v1.33.2 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 31000 # sample apps
    hostPort: 31000
  - containerPort: 31001 # hubble ui
    hostPort: 31001
- role: worker
  extraPortMappings:
  - containerPort: 31002 # sample apps
    hostPort: 31002
networking:
  podSubnet: "10.1.0.0/16"
  serviceSubnet: "10.3.0.0/16"
  disableDefaultCNI: true
  kubeProxyMode: none
EOF

# 설치 확인
kubectl config get-contexts 
CURRENT   NAME        CLUSTER     AUTHINFO    NAMESPACE
*         kind-east   kind-east   kind-east   
          kind-west   kind-west   kind-west 

kubectl config set-context kind-east
kubectl get node -v=6 --context kind-east
kubectl get node -v=6
kubectl get node -v=6 --context kind-west
cat ~/.kube/config

kubectl get pod -A
kubectl get pod -A --context kind-west

# 노드에 기본 툴 설치
docker exec -it east-control-plane sh -c 'apt update && apt install tree psmisc lsof wget net-tools dnsutils tcpdump ngrep iputils-ping git -y'
docker exec -it east-worker sh -c 'apt update && apt install tree psmisc lsof wget net-tools dnsutils tcpdump ngrep iputils-ping git -y'

# alias 설정
alias kwest='kubectl --context kind-west'
alias keast='kubectl --context kind-east'

# 확인
kwest get node -owide
keast get node -owide

각각에 cni를 설치해준다.
이때 클러스터 설정을 같이 넣어주는 것을 명심하자.
추가적으로 ip masq agent 세팅도 해주었다.

# cilium cli 설치
brew install cilium-cli # macOS
https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/#install-the-cilium-cli # Windwos WSL2

# cilium cli 로 cilium cni 설치해보기 : dry-run
cilium install --version 1.17.6 --set ipam.mode=kubernetes \
--set kubeProxyReplacement=true --set bpf.masquerade=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set operator.replicas=1 --set debug.enabled=true \
--set routingMode=native --set autoDirectNodeRoutes=true --set ipv4NativeRoutingCIDR=10.0.0.0/16 \
--set ipMasqAgent.enabled=true --set ipMasqAgent.config.nonMasqueradeCIDRs='{10.1.0.0/16}' \
--set cluster.name=west --set cluster.id=1 \
--context kind-west --dry-run-helm-values

# cilium cli 로 cilium cni 설치
cilium install --version 1.17.6 --set ipam.mode=kubernetes \
--set kubeProxyReplacement=true --set bpf.masquerade=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set operator.replicas=1 --set debug.enabled=true \
--set routingMode=native --set autoDirectNodeRoutes=true --set ipv4NativeRoutingCIDR=10.0.0.0/16 \
--set ipMasqAgent.enabled=true --set ipMasqAgent.config.nonMasqueradeCIDRs='{10.1.0.0/16}' \
--set cluster.name=west --set cluster.id=1 \
--context kind-west

watch kubectl get pod -n kube-system --context kind-west


# dry-run
cilium install --version 1.17.6 --set ipam.mode=kubernetes \
--set kubeProxyReplacement=true --set bpf.masquerade=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set operator.replicas=1 --set debug.enabled=true \
--set routingMode=native --set autoDirectNodeRoutes=true --set ipv4NativeRoutingCIDR=10.1.0.0/16 \
--set ipMasqAgent.enabled=true --set ipMasqAgent.config.nonMasqueradeCIDRs='{10.0.0.0/16}' \
--set cluster.name=east --set cluster.id=2 \
--context kind-east --dry-run-helm-values

cilium install --version 1.17.6 --set ipam.mode=kubernetes \
--set kubeProxyReplacement=true --set bpf.masquerade=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set operator.replicas=1 --set debug.enabled=true \
--set routingMode=native --set autoDirectNodeRoutes=true --set ipv4NativeRoutingCIDR=10.1.0.0/16 \
--set ipMasqAgent.enabled=true --set ipMasqAgent.config.nonMasqueradeCIDRs='{10.0.0.0/16}' \
--set cluster.name=east --set cluster.id=2 \
--context kind-east

watch kubectl get pod -n kube-system --context kind-east


# 확인
kwest get pod -A && keast get pod -A
cilium status --context kind-west
cilium status --context kind-east
cilium config view --context kind-west
cilium config view --context kind-east
kwest exec -it -n kube-system ds/cilium -- cilium status --verbose
keast exec -it -n kube-system ds/cilium -- cilium status --verbose

kwest -n kube-system exec ds/cilium -c cilium-agent -- cilium-dbg bpf ipmasq list
keast -n kube-system exec ds/cilium -c cilium-agent -- cilium-dbg bpf ipmasq list

# coredns 확인 : 둘 다, cluster.local 기본 도메인 네임 사용 중
kubectl describe cm -n kube-system coredns --context kind-west | grep kubernetes
    kubernetes cluster.local in-addr.arpa ip6.arpa {

kubectl describe cm -n kube-system coredns --context kind-west | grep kubernetes
    kubernetes cluster.local in-addr.arpa ip6.arpa {

# k9s 사용 시
k9s --context kind-west
k9s --context kind-east


# 삭제 시
# cilium uninstall --context kind-west
# cilium uninstall --context kind-east

→ Native Routing + 같은 네트워크 내에서 ClusterMesh 설정 시, 자동으로 라우팅 주입!

클러스터 메시 설정

라우팅 정보가 안 잡혀있다.

# 라우팅 정보 확인
docker exec -it west-control-plane ip -c route
docker exec -it west-worker ip -c route
docker exec -it east-control-plane ip -c route
docker exec -it east-worker ip -c route

아직 서로 통신할 시크릿 정보는 없다.
그래서 이걸 먼저 세팅해준다.

# Specify the Cluster Name and ID : 이미 설정 되어 있음

# Shared Certificate Authority
keast get secret -n kube-system cilium-ca
keast delete secret -n kube-system cilium-ca

kubectl --context kind-west get secret -n kube-system cilium-ca -o yaml | \
kubectl --context kind-east create -f -

keast get secret -n kube-system cilium-ca

클러스터 메시 활성화

# 모니터링 : 신규 터미널 2개
cilium clustermesh status --context kind-west --wait  
cilium clustermesh status --context kind-east --wait


# Enable Cluster Mesh : 간단한 실습 환경으로 NodePort 로 진행
cilium clustermesh enable --service-type NodePort --enable-kvstoremesh=false --context kind-west
cilium clustermesh enable --service-type NodePort --enable-kvstoremesh=false --context kind-east

kvstore는 멀까

# 32379 NodePort 정보 : clustermesh-apiserver 서비스 정보
kwest get svc,ep -n kube-system clustermesh-apiserver --context kind-west
NAME                            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/clustermesh-apiserver   NodePort   10.2.216.182   <none>        2379:32379/TCP   65s

NAME                              ENDPOINTS         AGE
endpoints/clustermesh-apiserver   10.0.0.195:2379   65s # 대상 파드는 clustermesh-apiserver 파드 IP

kwest get pod -n kube-system -owide | grep clustermesh


keast get svc,ep -n kube-system clustermesh-apiserver --context kind-east
NAME                            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/clustermesh-apiserver   NodePort   10.3.252.188   <none>        2379:32379/TCP   43s

NAME                              ENDPOINTS         AGE
endpoints/clustermesh-apiserver   10.1.0.206:2379   65s # 대상 파드는 clustermesh-apiserver 파드 IP

keast get pod -n kube-system -owide | grep clustermesh

서로를 위한 노드포트 서비스가 세팅된다.
잡으로 작업이 진행된다.

최종 명령어는 connect이다.

# 모니터링 : 신규 터미널 2개
watch -d "cilium clustermesh status --context kind-west --wait"
watch -d "cilium clustermesh status --context kind-east --wait"


# Connect Clusters
cilium clustermesh connect --context kind-west --destination-context kind-east
# 확인
cilium clustermesh status --context kind-west --wait
cilium clustermesh status --context kind-east --wait

# 
kubectl exec -it -n kube-system ds/cilium -c cilium-agent --context kind-west -- cilium-dbg troubleshoot clustermesh
kubectl exec -it -n kube-system ds/cilium -c cilium-agent --context kind-east -- cilium-dbg troubleshoot clustermesh

# 확인
kwest get pod -A && keast get pod -A
cilium status --context kind-west
cilium status --context kind-east
cilium clustermesh status --context kind-west
cilium clustermesh status --context kind-east
cilium config view --context kind-west
cilium config view --context kind-east
kwest exec -it -n kube-system ds/cilium -- cilium status --verbose
keast exec -it -n kube-system ds/cilium -- cilium status --verbose

헬름 설정으로도 들어간다.
어떻게 서로를 연결하는지, tls는 어떻게 되는지, 나온다.
여기에 인증서 갱신이 크론잡으로 되도록 설정된 것이 보인다.

#
helm get values -n kube-system cilium --kube-context kind-west 
...
cluster:
  id: 1
  name: west
clustermesh:
  apiserver:
    kvstoremesh:
      enabled: false
    service:
      type: NodePort
    tls:
      auto:
        enabled: true
        method: cronJob
        schedule: 0 0 1 */4 *
  config:
    clusters:
    - ips:
      - 172.18.0.4
      name: east
      port: 32379
    enabled: true
  useAPIServer: true
...

helm get values -n kube-system cilium --kube-context kind-east 
...
cluster:
  id: 2
  name: east
clustermesh:
  apiserver:
    kvstoremesh:
      enabled: false
    service:
      type: NodePort
    tls:
      auto:
        enabled: true
        method: cronJob
        schedule: 0 0 1 */4 *
  config:
    clusters:
    - ips:
      - 172.18.0.3
      name: west
      port: 32379
    enabled: true
  useAPIServer: true
...

파드간 라우팅 테이블이 바로 설정돼서 정말 멀티클러스터로서 사용이 가능해진다.

# 라우팅 정보 확인 : 클러스터간 PodCIDR 라우팅 주입 확인!
docker exec -it west-control-plane ip -c route
docker exec -it west-worker ip -c route
docker exec -it east-control-plane ip -c route
docker exec -it east-worker ip -c route

허블로 확인해본다.

# 설정
helm upgrade cilium cilium/cilium --version 1.17.6 --namespace kube-system --reuse-values \
--set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
--set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30001 --kube-context kind-west
kwest -n kube-system rollout restart ds/cilium

## 혹은 cilium hubble enable --ui --relay --context kind-west
## kubectl --context kind-west patch svc -n kube-system hubble-ui -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8081, "nodePort": 30001}]}}'


# 설정
helm upgrade cilium cilium/cilium --version 1.17.6 --namespace kube-system --reuse-values \
--set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
--set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=31001 --kube-context kind-east
kwest -n kube-system rollout restart ds/cilium

## 혹은 cilium hubble enable --ui --relay --context kind-east
## kubectl --context kind-east patch svc -n kube-system hubble-ui -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8081, "nodePort": 31001}]}}'


# 확인
kwest get svc,ep -n kube-system hubble-ui --context kind-west
keast get svc,ep -n kube-system hubble-ui --context kind-east

# hubble-ui 접속 시
open http://localhost:30001
open http://localhost:31001

통신 확인

이제 통신을 확인해본다.
이 스펙으로 각 클러스터에 설정을 넣어본다.

apiVersion: v1
kind: Pod
metadata:
  name: curl-pod
  labels:
    app: curl
spec:
  containers:
  - name: curl
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0

ip 기반으로는 바로 통신이 가능하다.


# 확인
kwest get pod -A && keast get pod -A
kwest get pod -owide && keast get pod -owide
NAME       READY   STATUS    RESTARTS   AGE   IP           NODE                 NOMINATED NODE   READINESS GATES
curl-pod   1/1     Running   0          43s   10.0.0.144   west-control-plane   <none>           <none>
NAME       READY   STATUS    RESTARTS   AGE   IP           NODE                 NOMINATED NODE   READINESS GATES
curl-pod   1/1     Running   0          36s   10.1.0.128   east-control-plane   <none>           <none>

#
kubectl exec -it curl-pod --context kind-west -- ping -c 1 10.1.0.128
64 bytes from 10.1.0.128: icmp_seq=1 ttl=62 time=0.877 ms

kubectl exec -it curl-pod --context kind-west -- ping 10.1.0.128

# 목적지 파드에서 tcpdump 로 확인 : NAT 없이 직접 라우팅.
kubectl exec -it curl-pod --context kind-east -- tcpdump -i eth0 -nn

# 목적지 k8s 노드?에서 icmp tcpdump 로 확인 : 다른곳 경유하지 않고 직접 노드에서 파드로 인입 확인
docker exec -it east-control-plane tcpdump -i any icmp -nn
docker exec -it east-worker tcpdump -i any icmp -nn

kubectl exec -it curl-pod --context kind-east -- ping -c 1 10.0.0.144
64 bytes from 10.0.0.144: icmp_seq=1 ttl=62 time=1.24 ms

허블로 보면 보인다.
패킷으로 떠도 보인다.
라우팅 테이블로 설정돼서 바로 들어간다.
ip masq agent가 설정돼 snat도 일어나지 않는다.

이제 서비스를 테스트해본다.
서비스부터는 dns까지도 세팅이 돼야 하기에 난이도가 조금 더 올라간다.
각 서비스에 어노테이션을 달아주는 것을 확인하자.
실리움 오퍼레이터는 이 값을 기반으로 상대 서비스 도메인에 대해서도 인식하게 해준다.

cat << EOF | kubectl apply --context kind-west -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webpod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webpod
  template:
    metadata:
      labels:
        app: webpod
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - sample-app
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: webpod
        image: traefik/whoami
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: webpod
  labels:
    app: webpod
  annotations:
    service.cilium.io/global: "true"
spec:
  selector:
    app: webpod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
EOF


#
cat << EOF | kubectl apply --context kind-east -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webpod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webpod
  template:
    metadata:
      labels:
        app: webpod
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - sample-app
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: webpod
        image: traefik/whoami
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: webpod
  labels:
    app: webpod
  annotations:
    service.cilium.io/global: "true"
spec:
  selector:
    app: webpod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
EOF

확인해보면 아예 상대 클러스터로도 트래픽이 가도록 설정된 것이 보인다!

kwest get svc,ep webpod && keast get svc,ep webpod

kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity
ID   Frontend               Service Type   Backend
...
13   10.2.37.24:80/TCP       ClusterIP      1 => 10.1.1.89:80/TCP (active)      
                                            2 => 10.0.1.27:80/TCP (active)      
                                            3 => 10.1.1.213:80/TCP (active)     
                                            4 => 10.0.1.19:80/TCP (active) 
                                            
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity
ID   Frontend               Service Type   Backend
...
13   10.3.156.11:80/TCP     ClusterIP      1 => 10.1.1.89:80/TCP (active)      
                                           2 => 10.0.1.27:80/TCP (active)      
                                           3 => 10.1.1.213:80/TCP (active)     
                                           4 => 10.0.1.19:80/TCP (active) 
#
kubectl exec -it curl-pod --context kind-west -- ping -c 1 10.1.0.128
kubectl exec -it curl-pod --context kind-east -- ping -c 1 10.0.0.144

#
kubectl exec -it curl-pod --context kind-west -- sh -c 'while true; do curl -s --connect-timeout 1 webpod ; sleep 1; echo "---"; done;'
kubectl exec -it curl-pod --context kind-east -- sh -c 'while true; do curl -s --connect-timeout 1 webpod ; sleep 1; echo "---"; done;'

# 현재 Service Annotations 설정
kwest describe svc webpod | grep Annotations -A1
Annotations:              service.cilium.io/global: true
Selector:                 app=webpod

keast describe svc webpod | grep Annotations -A1
Annotations:              service.cilium.io/global: true
Selector:                 app=webpod


# 모니터링 : 반복 접속해두기
kubectl exec -it curl-pod --context kind-west -- sh -c 'while true; do curl -s --connect-timeout 1 webpod ; sleep 1; echo "---"; done;'


#
kwest scale deployment webpod --replicas 1
kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity

# 로컬 k8s 에 목적지가 없을 경우 어떻게 되나요?
kwest scale deployment webpod --replicas 0
kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity

#
kwest scale deployment webpod --replicas 2
kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list --clustermesh-affinity


# tcpdump 확인 : dataplane flow 확인
docker exec -it west-control-plane tcpdump -i any tcp port 80 -nnq 
docker exec -it west-worker tcpdump -i any tcp port 80 -nnq
docker exec -it east-control-plane tcpdump -i any tcp port 80 -nnq 
docker exec -it east-worker tcpdump -i any tcp port 80 -nnq

스텁 서비스가 구성된 상황인데, dns는 어떻게 되려나

몇가지 설정 - 어피니티 로컬 , 어피니티, 쉐어드

회선 비용을 절약하기 위해 서로에게는 최대한 안들어가게 하고 시다면 어노테이션을 추가한다.
https://docs.cilium.io/en/stable/network/clustermesh/affinity/

클러스터메시 api server

서로 몇가지 구분이 되는 지점이 있다.
서로 노드 리스트를 인식할 때는 서로 source를 clustermesh로 인식

kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium node list 
Name                      IPv4 Address   Endpoint CIDR   IPv6 Address   Endpoint CIDR   Source
east/east-control-plane   172.18.0.5     10.1.0.0/24                                    clustermesh
east/east-worker          172.18.0.4     10.1.1.0/24                                    clustermesh
west/west-control-plane   172.18.0.2     10.0.0.0/24                                    custom-resource
west/west-worker          172.18.0.3     10.0.1.0/24                                    local

keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium node list            
Name                      IPv4 Address   Endpoint CIDR   IPv6 Address   Endpoint CIDR   Source
east/east-control-plane   172.18.0.5     10.1.0.0/24                                    custom-resource
east/east-worker          172.18.0.4     10.1.1.0/24                                    local
west/west-control-plane   172.18.0.2     10.0.0.0/24                                    clustermesh
west/west-worker          172.18.0.3     10.0.1.0/24                                    clustermesh

kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium identity list
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium identity list

kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium bpf ipcache list
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium bpf ipcache list
kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium map get cilium_ipcache
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium map get cilium_ipcache


kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list
keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium service list

kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium bpf lb list                      
10.2.127.79:443/TCP (0)     0.0.0.0:0 (2) (0) [ClusterIP, InternalLocal, non-routable] 

keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium bpf lb list                      
10.3.196.180:443/TCP (0)   0.0.0.0:0 (2) (0) [ClusterIP, InternalLocal, non-routable]

etcd를 보자.
서로의 글로벌 아이덴티티 설정이 필요하다.
그래서 별도의 etcd가 또 돌아간다!

#
kubectl describe pod -n kube-system -l k8s-app=clustermesh-apiserver
...
Containers:
  etcd:
    Container ID:  containerd://7668abdd87c354ab9295ff9f0aa047b3bd658a8671016c4564a1045f9e32cb9f
    Image:         quay.io/cilium/clustermesh-apiserver:v1.17.6@sha256:f619e97432db427e1511bf91af3be8ded418c53a353a09629e04c5880659d1df
    Image ID:      quay.io/cilium/clustermesh-apiserver@sha256:f619e97432db427e1511bf91af3be8ded418c53a353a09629e04c5880659d1df
    Ports:         2379/TCP, 9963/TCP
    Host Ports:    0/TCP, 0/TCP
    Command:
      /usr/bin/etcd
    Args:
      --data-dir=/var/run/etcd
      --name=clustermesh-apiserver
      --client-cert-auth
      --trusted-ca-file=/var/lib/etcd-secrets/ca.crt
      --cert-file=/var/lib/etcd-secrets/tls.crt
      --key-file=/var/lib/etcd-secrets/tls.key
      --listen-client-urls=https://127.0.0.1:2379,https://[$(HOSTNAME_IP)]:2379
      --advertise-client-urls=https://[$(HOSTNAME_IP)]:2379
      --initial-cluster-token=$(INITIAL_CLUSTER_TOKEN)
      --auto-compaction-retention=1
      --listen-metrics-urls=http://[$(HOSTNAME_IP)]:9963
      --metrics=basic
  ...
  apiserver:
    Container ID:  containerd://96da1c1ca39cb54d9e4def9333195f9a3812bf4978adcbe72bf47202b029e28d
    Image:         quay.io/cilium/clustermesh-apiserver:v1.17.6@sha256:f619e97432db427e1511bf91af3be8ded418c53a353a09629e04c5880659d1df
    Image ID:      quay.io/cilium/clustermesh-apiserver@sha256:f619e97432db427e1511bf91af3be8ded418c53a353a09629e04c5880659d1df
    Ports:         9880/TCP, 9962/TCP
    Host Ports:    0/TCP, 0/TCP
    Command:
      /usr/bin/clustermesh-apiserver
    Args:
      clustermesh
      --debug
      --cluster-name=$(CLUSTER_NAME)
      --cluster-id=$(CLUSTER_ID)
      --kvstore-opt=etcd.config=/var/lib/cilium/etcd-config.yaml
      --kvstore-opt=etcd.qps=20
      --kvstore-opt=etcd.bootstrapQps=10000
      --max-connected-clusters=255
      --health-port=9880
      --enable-external-workloads=false
      --prometheus-serve-addr=:9962
      --controller-group-metrics=all

# etcd 컨터이너 로그 확인
kubectl logs -n kube-system deployment/clustermesh-apiserver -c etcd

# apiserver 컨터이너 로그 확인
kubectl logs -n kube-system deployment/clustermesh-apiserver -c apiserver
#
kwest exec -it -n kube-system ds/cilium -c cilium-agent -- cilium status --all-clusters
ClusterMesh:            1/1 remote clusters ready, 1 global-services
   west: ready, 2 nodes, 9 endpoints, 7 identities, 1 services, 0 MCS-API service exports, 0 reconnections (last: never)
   └  etcd: 1/1 connected, leases=0, lock leases=0, has-quorum=true: endpoint status checks are disabled, ID: da1e6d481fd94dd
   └  remote configuration: expected=true, retrieved=true, cluster-id=1, kvstoremesh=false, sync-canaries=true, service-exports=disabled
   └  synchronization status: nodes=true, endpoints=true, identities=true, services=true

keast exec -it -n kube-system ds/cilium -c cilium-agent -- cilium status --all-clusters
ClusterMesh:            1/1 remote clusters ready, 1 global-services
   west: ready, 2 nodes, 9 endpoints, 7 identities, 1 services, 0 MCS-API service exports, 0 reconnections (last: never)
   └  etcd: 1/1 connected, leases=0, lock leases=0, has-quorum=true: endpoint status checks are disabled, ID: da1e6d481fd94dd
   └  remote configuration: expected=true, retrieved=true, cluster-id=1, kvstoremesh=false, sync-canaries=true, service-exports=disabled
   └  synchronization status: nodes=true, endpoints=true, identities=true, services=true

아예 각 컴포넌트에 접근해서 보자.

# etcd 컨테이너 bash 진입 후 확인
# krew pexec 플러그인 활용 https://github.com/ssup2/kpexec
kubectl get pod -n kube-system -l k8s-app=clustermesh-apiserver
DPOD=clustermesh-apiserver-5cf45db9cc-zxhsd

kubectl pexec $DPOD -it -T -n kube-system -- bash
------------------------------------------------
ps -ef
ps -ef -T -o pid,ppid,comm,args
ps -ef -T -o args
COMMAND
/usr/bin/etcd --data-dir=/var/run/etcd --name=clustermesh-apiserver --client-cert-auth --trusted-ca-file=/var/lib/etcd-se

cat /proc/1/cmdline ; echo
/usr/bin/etcd--data-dir=/var/run/etcd--name=clustermesh-apiserver--client-cert-auth--trusted-ca-file=/var/lib/etcd-secrets/ca.crt--cert-file=/var/lib/etcd-secrets/tls.crt--key-file=/var/lib/etcd-secrets/tls.key--listen-client-urls=https://127.0.0.1:2379,https://[10.1.1.243]:2379--advertise-client-urls=https://[10.1.1.243]:2379--initial-cluster-token=c044b25f-dfd4-4eb5-b3ab-05dbfb60117c--auto-compaction-retention=1--listen-metrics-urls=http://[10.1.1.243]:9963--metrics=basic

ss -tnlp
ss -tnp
ESTAB     0          0                 10.1.1.243:2379             172.18.0.5:51880      users:(("etcd",pid=1,fd=15))     
ESTAB     0          0                 10.1.1.243:2379             172.18.0.5:59850      users:(("etcd",pid=1,fd=14)) 

exit
------------------------------------------------

kubectl pexec $DPOD -it -T -n kube-system -c apiserver -- bash
------------------------------------------------
ps -ef
ps -ef -T -o pid,ppid,comm,args
ps -ef -T -o args
cat /proc/1/cmdline ; echo
usr/bin/clustermesh-apiserverclustermesh--debug--cluster-name=east--cluster-id=2--kvstore-opt=etcd.config=/var/lib/cilium/etcd-config.yaml--kvstore-opt=etcd.qps=20--kvstore-opt=etcd.bootstrapQps=10000--max-connected-clusters=255--health-port=9880--enable-external-workloads=false--prometheus-serve-addr=:9962--controller-group-metrics=all

ss -tnlp
ss -tnp
ESTAB    0         0                127.0.0.1:42286          127.0.0.1:2379     users:(("clustermesh-api",pid=1,fd=7))       
ESTAB    0         0               10.1.1.243:38300         172.18.0.5:6443     users:(("clustermesh-api",pid=1,fd=6)) 

exit
------------------------------------------------

mcs api

멀티클러스터 서비스 api
이건 실리움 전용이 아니라 현재 쿠버네티스에서 kep로 올라온 내용인데 실리움이 개발 중인 내용이다.
https://github.com/kubernetes/enhancements/blob/master/keps/sig-multicluster/1645-multi-cluster-services-api/README.md

이전 글, 다음 글

다른 글 보기

이름 index noteType created
1W - 실리움 기본 소개 1 published 2025-07-19
1W - 클러스터 세팅 및 cni 마이그레이션 2 published 2025-07-19
1W - 기본 실리움 탐색 및 통신 확인 3 published 2025-07-19
2W - 허블 기반 모니터링 4 published 2025-07-26
2W - 프로메테우스와 그라파나를 활용한 모니터링 5 published 2025-07-26
3W - 실리움 기본 - IPAM 6 published 2025-08-02
3W - 실리움 기본 - Routing, Masq, IP Frag 7 published 2025-08-02
4W - 실리움 라우팅 모드 실습 - native, vxlan, geneve 8 published 2025-08-09
4W - 실리움 로드밸런서 기능 - 서비스 IP, L2 9 published 2025-08-09
5W - BGP 실습 10 published 2025-08-16
5W - 클러스터 메시 11 published 2025-08-16

관련 문서

지식 문서, EXPLAIN

이름12is-folder생성 일자
E-이스티오 컨트롤 플레인 성능 최적화false2025-05-18 02:29
서비스 메시- 2024-05-21
Gateway APIfalse2025-01-06 17:51
Istio Securitytrue2025-05-04 19:58
사이드카 모드false2025-05-18 03:27
pilot-agentfalse2025-04-28 23:26
Istiotrue2025-04-07 14:26
Kialifalse2025-04-28 23:41
Amazon VPC Latticefalse2025-04-23 09:11
E-이스티오의 데이터 플레인 트래픽 세팅 원리false2025-05-27 21:55
앰비언트 모드false2025-06-02 14:51
메시 배포 모델false2025-05-21 13:36

기타 문서

Z0-연관 knowledge, Z1-트러블슈팅 Z2-디자인,설계, Z3-임시, Z5-프로젝트,아카이브, Z8,9-미분류,미완
이름4코드타입생성 일자
1W - 서비스 메시와 이스티오Z8published2025-04-10 20:04
8W - 엔보이와 iptables 뜯어먹기Z8published2025-06-01 12:14
4W - 번외 - 트레이싱용 심플 메시 서버 개발Z8published2025-05-03 22:48
6W - 이스티오 컨트롤 플레인 성능 최적화Z8published2025-05-18 02:29

참고


  1. https://docs.cilium.io/en/stable/network/clustermesh/intro/ ↩︎